﻿using Mapster;
using SqlSugar;
using Zhp.Common.Extention;
using Zhp.Common.WebApp;
using Zhp.Entity.Sys;
using Zhp.Entity.SysEnum;
using Zhp.IService.Sys;
using Zhp.Model.Sys;
using Zhp.Service.Base;
using Zhp.SqlSugar.Repository;

namespace Zhp.Service.Sys
{
    public class SysMenuService : BaseService<SysMenu>, ISysMenuService
    {
        IBaseRepository<SysUserRole> _sysUserRoleRep;
        IBaseRepository<SysUserMenu> _sysUserMenuRep;
        IBaseRepository<SysRoleMenu> _sysRoleMenuRep;
        public SysMenuService(ICurrentUser currentUser, IBaseRepository<SysMenu> rep, IBaseRepository<SysUserRole> sysUserRoleRep, IBaseRepository<SysUserMenu> sysUserMenuRep, IBaseRepository<SysRoleMenu> sysRoleMenuRep)
        {
            _currentUser = currentUser;
            _rep = rep;
            _sysUserRoleRep = sysUserRoleRep;
            _sysUserMenuRep = sysUserMenuRep;
            _sysRoleMenuRep = sysRoleMenuRep;
        }

        public async Task<List<MenuModel>> GetMenu(MenuQuery query)
        {
            var menuList = await _rep.GetPageListAsync(new List<IConditionalModel>
            {
                new ConditionalModel
                {
                     FieldName = "ParentId",
                     ConditionalType = ConditionalType.EqualNull,
                }
            }, query, x => x.Order, OrderByType.Asc);

            return menuList.Adapt<List<MenuModel>>();
        }

        public async Task<List<MenuModel>> GetSubMenu(long Id)
        {
            var menuList = await _rep.GetListAsync(x => x.ParentId == Id);

            return menuList.OrderBy(x => x.Order).Adapt<List<MenuModel>>();
        }

        public async Task<List<MenuTreeModel>> GetParentMenuTree(long? Id)
        {
            var exp = new Expressionable<SysMenu>();

            exp.And(x => x.MenuType != MenuTypeEnum.Button);
            exp.AndIF(Id != null, c => c.Id != Id);
            
            var menuTree = await _rep.AsQueryable().Where(exp.ToExpression()).ToTreeAsync(x => x.Children, x => x.ParentId, null);

            return menuTree.Adapt<List<MenuTreeModel>>();
        }

        public async Task<bool> Create(MenuCreate create)
        {
            //根菜单路由必须以“/”开头
            MenuGroupRouterUrl(create);

            var menu = create.Adapt<SysMenu>();

            //更新父节点是否有子节点
            if (create.ParentId > 0)
            {
                var pmenu = await _rep.GetByIdAsync(create.ParentId);
                pmenu.HasChildren = true;
                await _rep.UpdateAsync(pmenu);
            }

            return await _rep.InsertAsync(menu);
        }

        public async Task<bool> Update(MenuCreate update)
        {
            //根菜单路由必须以“/”开头
            MenuGroupRouterUrl(update);

            var menu = await _rep.GetByIdAsync(update.Id);

            if (menu != null)
            {
                if (menu.ParentId != update.ParentId)
                {
                    //更新原来的父级是否有字节点
                    await UpdateHasChildren(menu);

                    //更新现在的父级是否有字节点
                    var newPMenu = await _rep.GetByIdAsync(update.ParentId);
                    if (newPMenu != null)
                    {
                        newPMenu.HasChildren = true;

                        await _rep.UpdateAsync(newPMenu);
                    }
                }

                update.Adapt(menu);

                return await _rep.UpdateAsync(menu);
            }

            return false;
        }

        /// <summary>
        /// 根菜单路由必须以“/”开头
        /// </summary>
        /// <param name="menu"></param>
        private void MenuGroupRouterUrl(MenuCreate menu)
        {
            char start = '/';
            if (menu.ParentId == null)
            {
                menu.RouterUrl = menu.RouterUrl.StartsWith(start) ? menu.RouterUrl : start + menu.RouterUrl;
            }
        }

        public async Task<bool> Delete(long id)
        {
            var menu = await _rep.GetByIdAsync(id);

            if (menu != null)
            {
                //删除所有子节点
                var subList = await _rep.AsQueryable().ToChildListAsync(x => x.ParentId, menu.Id, false);

                await _rep.DeleteAsync(subList);

                //更新父节点是否有子节点
                await UpdateHasChildren(menu);

                return await _rep.DeleteAsync(menu);
            }

            return false;
        }

        /// <summary>
        /// 更新原来父节点是否有子节点
        /// </summary>
        /// <param name="menu"></param>
        /// <returns></returns>
        private async Task UpdateHasChildren(SysMenu menu)
        {
            if (menu.ParentId > 0)
            {
                int hasChildren = await _rep.CountAsync(x => x.ParentId == menu.ParentId && x.Id != menu.Id);
                if (hasChildren == 0)
                {
                    var pMenu = await _rep.GetByIdAsync(menu.ParentId);

                    pMenu.HasChildren = false;

                    await _rep.UpdateAsync(pMenu);
                }
            }
        }


        public async Task<List<HomeMenuTreeModel>> GetHomeMenuList()
        {
            //用户所属角色菜单
            var userRoleList = await _sysUserRoleRep.GetListAsync(x => x.UserId == _currentUser.UserId);
            var roleMenuList = await _sysRoleMenuRep.GetListAsync(x => userRoleList.Select(x => x.RoleId).Contains(x.RoleId));
            //用户菜单
            var userMenuList = await _sysUserMenuRep.GetListAsync(x => x.UserId == _currentUser.UserId);

            var menuIdList = new List<long>();
            menuIdList.AddRange(roleMenuList.Select(x => x.MenuId));
            menuIdList.AddRange(userMenuList.Select(x => x.MenuId));

            var list = await _rep.GetListAsync(x => (x.MenuType == MenuTypeEnum.Group || x.MenuType == MenuTypeEnum.Menu) && menuIdList.Contains(x.Id));
            
            var rList = list.Adapt<List<HomeMenuTreeModel>>().OrderBy(x => x.Order).ToList();

            return rList.ToTree(x => x.Id, x => x.Children, x => x.ParentId, null);
        }

        public async Task<List<ButtonModel>> GetButtonList(long menuId)
        {
            //用户所属角色菜单
            var userRoleList = await _sysUserRoleRep.GetListAsync(x => x.UserId == _currentUser.UserId);
            var roleMenuList = await _sysRoleMenuRep.GetListAsync(x => userRoleList.Select(x => x.RoleId).Contains(x.RoleId));
            //用户菜单
            var userMenuList = await _sysUserMenuRep.GetListAsync(x => x.UserId == _currentUser.UserId);

            var menuIdList = new List<long>();
            menuIdList.AddRange(roleMenuList.Select(x => x.MenuId));
            menuIdList.AddRange(userMenuList.Select(x => x.MenuId));

            var list = await _rep.AsQueryable().ToChildListAsync(x => x.ParentId, menuId, false);

            var whereList = list.Where(x => (x.MenuType == MenuTypeEnum.List || x.MenuType == MenuTypeEnum.Button) && menuIdList.Contains(x.Id));

            var rList = whereList.Adapt<List<ButtonModel>>();

            return rList;
        }
    }
}
